//! 字符串(String)示例
//!
//! Rust 中有两种字符串类型：字符串字面量(&str)和 String 类型。

/// 创建字符串
#[test]
pub fn creating_strings() {
    // 创建新的空字符串
    let s = String::new();

    // 从字符串字面量创建 String
    let data = "initial contents";
    let s = data.to_string();

    // 直接从字符串字面量创建
    let s = "initial contents".to_string();

    // 使用 String::from 创建
    let s = String::from("initial contents");

    println!("创建字符串示例:");
    println!("空字符串: '{}'", s);
    println!("从字面量创建: '{}'", s);
    println!("使用 String::from: '{}'", s);

    // 创建一个空String
    let s = String::new();
    println!("空字符串: '{}'", s);

    // 将&str转换为 String
    let s1 = String::from("1");
    println!("初始字符串: '{}'", s1);
}

/// 更新字符串
#[test]
pub fn updating_strings() {
    // 使用 push_str 方法追加字符串 slice
    let mut s = String::from("foo");
    s.push_str("bar");
    println!("使用 push_str: '{}'", s);

    // 使用 push 方法追加单个字符
    s.push('!');
    println!("使用 push 添加字符: '{}'", s);

    // 使用 + 连接字符串
    let s1 = String::from("Hello, ");
    let s2 = String::from("world!");
    let s3 = s1 + &s2; // 注意：s1 被移动，不能再使用
    println!("使用 + 连接: '{}'", s3);

    // 使用 format! 宏连接字符串
    let s1 = String::from("tic");
    let s2 = String::from("tac");
    let s3 = String::from("toe");
    let s = format!("{}-{}-{}", s1, s2, s3);
    println!("使用 format! 连接: '{}'", s);

    // 将给定的字符串切片附加到此 String的末尾
    let mut s1 = String::from("1");
    s1.push_str("1");
    // 将给定 char 的附加到此 String末尾
    s1.push('1');
    println!("s1 is {}", s1);

    let data = "1";
    // 任何实现了 Display trait 的类型，字符串字面量 都可以使用to_string方法
    // String::from 函数和to_string方法是等价的
    let s2 = data.to_string();
    let s3 = s1 + &s2;
    println!("连接后的字符串: '{}'", s3);
}

/// 字符串索引
#[test]
pub fn string_indexing() {
    let s = String::from("hello");

    // 注意：Rust 中的字符串不支持直接索引访问
    // 下面的代码会导致编译错误：
    // let h = s[0];  // 错误！

    println!("字符串索引说明:");
    println!("字符串 '{}' 不能直接通过索引访问", s);
    println!("需要使用其他方法来访问字符串中的字符");
}

/// 切割字符串
#[test]
pub fn slicing_strings() {
    let s = String::from("hello 世界");

    // 获取字符串的一部分（字节切片）
    let slice = &s[0..5];
    println!("字节切片 [0..5]: '{}'", slice);

    // 注意：以 Unicode 标量值切割字符串可能不安全
    // 如果在字符的中间位置切割，程序会 panic
    // 例如：&s[0..7] 可能会导致运行时错误，因为"世"字符占3个字节

    let s = String::from("111111");
    println!("s len is {}", s.len());
    // 字符串切片语法糖
    let s1 = &s[..2];
    let s2 = &s[0..2];
    let s3 = &s[3..s.len()];
    let s4 = &s[3..];
    let s = format!("{}-{}-{}-{}", s1, s2, s3, s4);
    println!("s is {}", s);
}

/// 遍历字符串
#[test]
pub fn iterating_strings() {
    let s = String::from("hello 世界");

    // 按字节遍历
    println!("按字节遍历:");
    for b in s.bytes() {
        print!("{} ", b);
    }
    println!();

    // 按字符遍历
    println!("按字符遍历:");
    for c in s.chars() {
        print!("{} ", c);
    }
    println!();
}

/// 格式化宏示例
#[test]
pub fn format_macro() {
    // format宏测试
    let s1 = String::from("tic");
    let s2 = String::from("tac");
    let s3 = String::from("toe");

    let s = format!("{}-{}-{}", s1, s2, s3);
    println!("s is {}", s);
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_creating_strings() {
        creating_strings();
    }

    #[test]
    fn test_updating_strings() {
        updating_strings();
    }

    #[test]
    fn test_string_indexing() {
        string_indexing();
    }

    #[test]
    fn test_slicing_strings() {
        slicing_strings();
    }

    #[test]
    fn test_iterating_strings() {
        iterating_strings();
    }

    #[test]
    fn test_format_macro() {
        format_macro();
    }
}
